package com.hustcad.plm.pdm.user.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import com.hustcad.plm.pdm.common.util.CommonUtil;
import com.hustcad.plm.pdm.flowbusiness.model.entity.FlowObject;
import com.hustcad.plm.pdm.iteration.dto.TyplmCommonHistoryDTO;
import com.hustcad.plm.pdm.iteration.service.TyplmCommonHistoryService;
import com.hustcad.plm.pdm.partbom.dto.PartByFatherOidDTO;
import com.hustcad.plm.pdm.partbom.dto.PartUsageLink;
import com.hustcad.plm.pdm.partbom.service.TyplmPartBomService;
import com.hustcad.plm.pdm.partbom.service.TyplmPartService;
import com.hustcad.plm.pdm.partbom.service.TyplmPartUsageLinkService;
import com.hustcad.plm.pdm.partbom.service.view.TyplmViewDefService;
import com.hustcad.plm.pdm.partbom.vo.PartDetailsVO;
import com.hustcad.plm.pdm.partbom.vo.PartUsageLinkVO;
import com.jsyxdl.entity.PartUsageLinkDiffResultDTO;
import com.ty.basic.entity.IdentifierEntity;
import com.ty.basic.entity.part.PartDO;
import com.ty.basic.entity.view.ViewDefDO;

import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

public class ErpHistoricalVersion {
    public List<PartUsageLinkDiffResultDTO> getPartDiffResults(FlowObject flowObject){
        TyplmPartService typlmPartService = SpringUtil.getBean(TyplmPartService.class);
        TyplmCommonHistoryService typlmCommonHistoryService =  SpringUtil.getBean(TyplmCommonHistoryService.class);

        BigInteger newBOMPartOid = flowObject.getRefObjectOid();
        String coType = flowObject.getRefObjectOtype();
        PartDetailsVO newBOMPartDetailsVO = typlmPartService.queryPartDetails(newBOMPartOid, coType);

        IdentifierEntity identifierEntity = new IdentifierEntity();
        identifierEntity.setOidStr(newBOMPartDetailsVO.getOid());
        identifierEntity.setOtype(newBOMPartDetailsVO.getOtype());

        //获取所有历史版本
        List<TyplmCommonHistoryDTO> deffList = typlmCommonHistoryService.getVersionHistory(identifierEntity);
        PartByFatherOidDTO newFatherOidDTO = new PartByFatherOidDTO();
        newFatherOidDTO.setPartOid(String.valueOf(newBOMPartOid));
        List<PartUsageLink> newPartUsageLinks = this.queryPartUsageLinkByFatherOid(newFatherOidDTO);
        List<TyplmCommonHistoryDTO> clist = getCurrentAndPreviousMajorVersionLatest(deffList);

        List<PartUsageLinkDiffResultDTO> diffResults = new ArrayList<>();;
        if (clist.size() == 1) {
            if(deffList.size()>1){
                //如果没有大版本变更，判断小版本差异
//                PartByFatherOidDTO oldFatherOidDTO = new PartByFatherOidDTO();
//                oldFatherOidDTO.setPartOid(String.valueOf(deffList.get(1).getOid()));
//                List<PartUsageLink> oldPartUsageLinks = this.queryPartUsageLinkByFatherOid(oldFatherOidDTO);
//                diffResults = comparePartUsageLinks(newBOMPartDetailsVO,newPartUsageLinks, oldPartUsageLinks);
                diffResults = comparePartUsageLinks(newBOMPartDetailsVO,newPartUsageLinks, null);

            }
            else{
                diffResults = comparePartUsageLinks(newBOMPartDetailsVO,newPartUsageLinks, null);
            }
        }
        else {
            // 如果有多个版本，则需要比较差异并生成Excel文件
            PartByFatherOidDTO oldFatherOidDTO = new PartByFatherOidDTO();
            oldFatherOidDTO.setPartOid(String.valueOf(clist.get(1).getOid()));
            List<PartUsageLink> oldPartUsageLinks = this.queryPartUsageLinkByFatherOid(oldFatherOidDTO);
            //amount数量
            //value行号
            //unitKey单位（key值）
            //ibaAttributeMap，记录BOM的各种扩展属性，用户输入的时候才会有key和value，否则map是空的
            //aoid，父件的oid（特定版本的对象）
            //boid，子件的oid（master对象）
            // 比较差异
            diffResults = comparePartUsageLinks(newBOMPartDetailsVO,newPartUsageLinks, oldPartUsageLinks);
        }
        return diffResults;
    }
    /**
     * 获取当前大版本的最新小版本和上一个大版本的最新小版本
     * 该方法用于从给定的历史记录列表中筛选出当前大版本和前一个大版本的最新小版本
     *
     * @param historyList 一个包含TyplmCommonHistoryDTO对象的列表，这些对象代表不同的版本历史
     * @return 返回一个列表，其中包含当前大版本和前一个大版本的最新小版本的TyplmCommonHistoryDTO对象
     */
    public static List<TyplmCommonHistoryDTO> getCurrentAndPreviousMajorVersionLatest(List<TyplmCommonHistoryDTO> historyList) {
        if (historyList == null || historyList.isEmpty()) {
            return Collections.emptyList();
        }

        // 1. 获取每个大版本的最新小版本
        Map<String, TyplmCommonHistoryDTO> latestVersionsMap = new HashMap<>();
        for (TyplmCommonHistoryDTO item : historyList) {
            String major = item.getMajorVersion();
            String minor = item.getMinorVersion();

            if (!latestVersionsMap.containsKey(major) ||
                    latestVersionsMap.get(major).getMinorVersion().compareTo(minor) < 0) {
                latestVersionsMap.put(major, item);
            }
        }

        // 2. 排序大版本（降序）
        List<String> sortedMajors = new ArrayList<>(latestVersionsMap.keySet());
        sortedMajors.sort(Comparator.reverseOrder());

        // 3. 获取结果
        List<TyplmCommonHistoryDTO> result = new ArrayList<>();
        if (!sortedMajors.isEmpty()) {
            // 当前大版本
            result.add(latestVersionsMap.get(sortedMajors.get(0)));

            // 上一个大版本（如果存在）
            if (sortedMajors.size() > 1) {
                result.add(latestVersionsMap.get(sortedMajors.get(1)));
            }
        }

        return result;
    }

    public List<PartUsageLinkDiffResultDTO> comparePartUsageLinks(PartDetailsVO newBOMPartDetailsVO,
                                                                  List<PartUsageLink> newPartUsageLinks,
                                                                  List<PartUsageLink> oldPartUsageLinks) {
        TyplmPartService typlmPartService =SpringUtil.getBean(TyplmPartService.class);
        TyplmViewDefService typlmViewDefService = SpringUtil.getBean(TyplmViewDefService.class);


        List<ViewDefDO> viewDefDOList = new ArrayList();
        viewDefDOList.add(typlmViewDefService.getViewByName("Design"));
        List<BigInteger> viewDefOid = (List)viewDefDOList.stream().map(ViewDefDO::getOid).collect(Collectors.toList());

        List<PartUsageLinkDiffResultDTO> diffResults = new ArrayList<>();
        if (oldPartUsageLinks == null || oldPartUsageLinks.isEmpty()) {
            for (PartUsageLink newLink : newPartUsageLinks) {
                PartUsageLinkDiffResultDTO diffResult = new PartUsageLinkDiffResultDTO(newLink.getBoid(), "新增物料");
                List<PartDO> partDOS = typlmPartService.queryLastedByPartMasterListAndView(Arrays.asList(newLink.getBoid()), viewDefOid);
                PartDO partDO = partDOS.get(0);
                diffResult.setIdentifierDisplayName(partDO.getDisplayFullName());
                //TODO 获取原材料分类下的第一级分类名称
                PartDetailsVO partDetailsVO = typlmPartService.queryPartDetails(partDO.getOid(), "ty.inteplm.part.CTyPart");
                String materialType = partDetailsVO.getTypeName();
                diffResult.setMaterialType(materialType);

                diffResult.setName(partDetailsVO.getName());
                diffResult.setObjectNumber(partDetailsVO.getObjectNumber());
                diffResult.setUnitKey(newLink.getUnitkey());
                diffResult.setNewAmount(newLink.getAmount());
                diffResult.setAmountDiff(newLink.getAmount()); // 新增时，数量差值为新数量
                diffResult.setVersion(newBOMPartDetailsVO.getVersion());
                diffResult.setIteration(newBOMPartDetailsVO.getIteration());

                diffResults.add(diffResult);
            }
            //只有第一版的情况下直接返回最新版的数据
            return diffResults;
        }

        // 用于记录已经匹配的 boid
        Set<String> matchedBoids = new HashSet<>();
        // 遍历 newPartUsageLinks，检查新增或数量变化
        for (PartUsageLink newLink : newPartUsageLinks) {
            boolean found = false;
            for (PartUsageLink oldLink : oldPartUsageLinks) {
                if (newLink.getBoid().equals(oldLink.getBoid())) {
                    found = true;
                    matchedBoids.add(String.valueOf(newLink.getBoid()));

                    // 比较 amount
                    if (!newLink.getAmount().equals(oldLink.getAmount())) {
                        PartUsageLinkDiffResultDTO diffResult = new PartUsageLinkDiffResultDTO(newLink.getBoid(), "数量变化");
                        List<PartDO> partDOS = typlmPartService.queryLastedByPartMasterListAndView(Arrays.asList(newLink.getBoid()), viewDefOid);
                        PartDO partDO = partDOS.get(0);
                        diffResult.setIdentifierDisplayName(partDO.getDisplayFullName());
                        //TODO 获取原材料分类下的第一级分类名称
                        PartDetailsVO partDetailsVO = typlmPartService.queryPartDetails(partDO.getOid(), "ty.inteplm.part.CTyPart");
                        String materialType = partDetailsVO.getTypeName();
                        diffResult.setMaterialType(materialType);

                        diffResult.setOldAmount(oldLink.getAmount());
                        diffResult.setName(partDetailsVO.getName());
                        diffResult.setObjectNumber(partDetailsVO.getObjectNumber());
                        diffResult.setUnitKey(newLink.getUnitkey());

                        diffResult.setNewAmount(newLink.getAmount());
                        diffResult.setAmountDiff(newLink.getAmount() - oldLink.getAmount()); //同一个物料数量有差异，取差值
                        diffResults.add(diffResult);
                    }
                    break; // 找到匹配的 boid 后跳出内层循环
                }
            }

            // 如果没有找到匹配的 boid，说明是新增
            if (!found) {
                PartUsageLinkDiffResultDTO diffResult = new PartUsageLinkDiffResultDTO(newLink.getBoid(), "新增物料");
                List<PartDO> partDOS = typlmPartService.queryLastedByPartMasterListAndView(Arrays.asList(newLink.getBoid()), viewDefOid);
                PartDO partDO = partDOS.get(0);
                diffResult.setIdentifierDisplayName(partDO.getDisplayFullName());
                //TODO 获取原材料分类下的第一级分类名称
                PartDetailsVO partDetailsVO = typlmPartService.queryPartDetails(partDO.getOid(), "ty.inteplm.part.CTyPart");
                String materialType = partDetailsVO.getTypeName();
                diffResult.setMaterialType(materialType);

                diffResult.setName(partDetailsVO.getName());
                diffResult.setObjectNumber(partDetailsVO.getObjectNumber());
                diffResult.setUnitKey(newLink.getUnitkey());

                diffResult.setNewAmount(newLink.getAmount());
                diffResult.setAmountDiff(newLink.getAmount()); // 新增时，直接取当前数量即可
                diffResults.add(diffResult);
            }
        }

        // 遍历 oldPartUsageLinks，检查移除
        for (PartUsageLink oldLink : oldPartUsageLinks) {
            if (!matchedBoids.contains(String.valueOf(oldLink.getBoid()))) {
                PartUsageLinkDiffResultDTO diffResult = new PartUsageLinkDiffResultDTO(oldLink.getBoid(), "移除物料");
                List<PartDO> partDOS = typlmPartService.queryLastedByPartMasterListAndView(Arrays.asList(oldLink.getBoid()), viewDefOid);
                PartDO partDO = partDOS.get(0);
                diffResult.setIdentifierDisplayName(partDO.getDisplayFullName());
                //TODO 获取原材料分类下的第一级分类名称
                PartDetailsVO partDetailsVO = typlmPartService.queryPartDetails(partDO.getOid(), "ty.inteplm.part.CTyPart");
                String materialType = partDetailsVO.getTypeName();
                diffResult.setMaterialType(materialType);

                diffResult.setName(partDetailsVO.getName());
                diffResult.setObjectNumber(partDetailsVO.getObjectNumber());
                diffResult.setUnitKey(oldLink.getUnitkey());

                diffResult.setOldAmount(oldLink.getAmount());
                diffResult.setAmountDiff(-oldLink.getAmount()); // 移除时，数量差值为负的旧数量
                diffResults.add(diffResult);
            }
        }

        return diffResults;
    }

    public List<PartUsageLink> queryPartUsageLinkByFatherOid (PartByFatherOidDTO fatherOidDTO) {
        TyplmPartBomService typlmPartBomService = (TyplmPartBomService) SpringUtil.getBean(
                TyplmPartBomService.class);
        TyplmViewDefService typlmViewDefService = (TyplmViewDefService) SpringUtil.getBean(
                TyplmViewDefService.class);
        TyplmPartUsageLinkService typlmPartUsageLinkService = (TyplmPartUsageLinkService) SpringUtil.getBean(
                TyplmPartUsageLinkService.class);

        List<ViewDefDO> viewDefDOList = new ArrayList();
        viewDefDOList.add(typlmViewDefService.getViewByName("Design"));
        List<BigInteger> vieDefOid = (List)viewDefDOList.stream().map(ViewDefDO::getOid).collect(Collectors.toList());
        List<PartUsageLinkVO> partUsageLinkVOList = typlmPartUsageLinkService.querySonPartInfoWithViews(
                new BigInteger(fatherOidDTO.getPartOid()), true, CommonUtil.getUserOid(), vieDefOid);
        List<PartUsageLink>  partUsageLinkList = new ArrayList<>();
        for (PartUsageLinkVO partUsageLinkVO : partUsageLinkVOList) {
            PartUsageLink partUsageLink = typlmPartBomService.getPartUsageLinkInfo(partUsageLinkVO.getOid(), "ty.inteplm.part.CTyPartUsageLink");
            partUsageLinkList.add(partUsageLink);
        }
        return partUsageLinkList;
    }
}
